package com.bill.pokerbe.service;

import com.bill.pokerbe.model.Card;
import com.bill.pokerbe.model.CardCommon;
import com.bill.pokerbe.model.CardType;
import com.bill.pokerbe.model.ScoreAndWinType;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

@Service
public class CountService {
    private static final int TotalCard = 7;
    private static final int ChooseCard = 5;
    private long maxScore = 0;
    private boolean[] choose;

    private Card siTiaoCard;
    private Card siTiaoRemainCard;
    private Card huluCard;
    private Card huluRemainCard;


    private Card santiaoCard;

    private List<Card> santiaoRemainCardList;

    private Card liangDuiCard1;
    private Card liangDuiCard2;
    private Card liangDuiRemainCard;

    private Card duiziCard;
    private List<Card> duiziRemainCardList;

    List<Card> inputCardList;

    public CountService() {
        choose = new boolean[10];
    }

    public ScoreAndWinType getCardScore(List<Card> cardList) {
        maxScore = 0;
        Arrays.fill(choose, false);
        inputCardList = cardList;
        dfs(0, 0);
        return getScoreAndWinType(maxScore);
    }

    private ScoreAndWinType getScoreAndWinType(long maxScore) {
        long firstLevelScore = maxScore / 10000000000L;
        String winType = "";
        if (firstLevelScore == 90L) {
            winType = "同花顺";
        } else if (firstLevelScore == 80L) {
            winType = "四条";
        } else if (firstLevelScore == 70L) {
            winType = "葫芦";
        } else if (firstLevelScore == 60L) {
            winType = "同花";
        } else if (firstLevelScore == 50L) {
            winType = "顺子";
        } else if (firstLevelScore == 40L) {
            winType = "三条";
        } else if (firstLevelScore == 30L) {
            winType = "两对";
        } else if (firstLevelScore == 20L) {
            winType = "对子";
        } else if (firstLevelScore == 10L) {
            winType = "高牌";
        }
        return new ScoreAndWinType(maxScore, winType);
    }

    private void dfs(int step, int count) {
        if (step == TotalCard) {
            if (count == ChooseCard) {
                maxScore = Math.max(calcScore(), maxScore);
            }
            return;
        }
        choose[step] = true;
        dfs(step + 1, count + 1);
        choose[step] = false;
        dfs(step + 1, count);
    }

    private long calcScore() {
        long[] scores = new long[6];
        List<Card> cardList = new ArrayList<>();
        List<Card> restCardList = new ArrayList<>();
        for (int i = 0; i < TotalCard; i++) {
            if (choose[i]) {
                cardList.add(inputCardList.get(i));
            } else {
                restCardList.add(inputCardList.get(i));
            }
        }
        int a = 1;
        cardList.sort(((o1, o2) -> (int) (CardCommon.GetCardNumberScore(o2.CardNum) - CardCommon.GetCardNumberScore(o1.CardNum))));
        restCardList.sort(((o1, o2) -> (int) (CardCommon.GetCardNumberScore(o2.CardNum) - CardCommon.GetCardNumberScore(o1.CardNum))));

        if (isTongHuaShun(cardList)) {
            scores[0] = 90;
            scores[1] = CardCommon.GetCardNumberScore(cardList.get(0).CardNum);
        } else if (isSitiao(cardList)) {
            scores[0] = 80;
            scores[1] = CardCommon.GetCardNumberScore(siTiaoCard.CardNum);
            scores[2] = CardCommon.GetCardNumberScore(siTiaoRemainCard.CardNum);
        } else if (isHulu(cardList)) {
            scores[0] = 70;
            scores[1] = CardCommon.GetCardNumberScore(huluCard.CardNum);
            scores[2] = CardCommon.GetCardNumberScore(huluRemainCard.CardNum);
        } else if (isTonghua(cardList)) {
            scores[0] = 60;
            scores[1] = CardCommon.GetCardNumberScore(cardList.get(0).CardNum);
            scores[2] = CardCommon.GetCardNumberScore(cardList.get(1).CardNum);
            scores[3] = CardCommon.GetCardNumberScore(cardList.get(2).CardNum);
            scores[4] = CardCommon.GetCardNumberScore(cardList.get(3).CardNum);
            scores[5] = CardCommon.GetCardNumberScore(cardList.get(4).CardNum);
        } else if (isShunZi(cardList)) {
            scores[0] = 50;
            scores[1] = CardCommon.GetCardNumberScore(cardList.get(0).CardNum);
        } else if (isSantiao(cardList)) {
            scores[0] = 40;
            scores[1] = CardCommon.GetCardNumberScore(santiaoCard.CardNum);
            scores[2] = CardCommon.GetCardNumberScore(santiaoRemainCardList.get(0).CardNum);
            scores[3] = CardCommon.GetCardNumberScore(santiaoRemainCardList.get(1).CardNum);
        } else if (isLiangDui(cardList)) {
            scores[0] = 30;
            scores[1] = CardCommon.GetCardNumberScore(liangDuiCard1.CardNum);
            scores[2] = CardCommon.GetCardNumberScore(liangDuiCard2.CardNum);
            scores[3] = CardCommon.GetCardNumberScore(liangDuiRemainCard.CardNum);
        } else if (isDuiZi(cardList)) {
            scores[0] = 20;
            scores[1] = CardCommon.GetCardNumberScore(duiziCard.CardNum);
            scores[2] = CardCommon.GetCardNumberScore(duiziRemainCardList.get(0).CardNum);
            scores[3] = CardCommon.GetCardNumberScore(duiziRemainCardList.get(1).CardNum);
            scores[4] = CardCommon.GetCardNumberScore(duiziRemainCardList.get(2).CardNum);
        } else {//高牌
            scores[0] = 10;
            scores[1] = CardCommon.GetCardNumberScore(cardList.get(0).CardNum);
            scores[2] = CardCommon.GetCardNumberScore(cardList.get(1).CardNum);
            scores[3] = CardCommon.GetCardNumberScore(cardList.get(2).CardNum);
            scores[4] = CardCommon.GetCardNumberScore(cardList.get(3).CardNum);
            scores[5] = CardCommon.GetCardNumberScore(cardList.get(4).CardNum);
        }

        long totalScore = 0;
        for (long score : scores) {
            totalScore *= 100;
            totalScore += score;
        }
        return totalScore;
    }


    private boolean isTongHuaShun(List<Card> cardList) {
        return isTonghua(cardList) && isShunZi(cardList);
    }

    private boolean isSitiao(List<Card> cardList) {
        boolean first4same = true;
        for (int i = 1; i < ChooseCard - 1; i++) {
            if (!Objects.equals(cardList.get(i).CardNum, cardList.get(0).CardNum)) {
                first4same = false;
                break;
            }
        }
        if (first4same) {
            siTiaoCard = cardList.get(0);
            siTiaoRemainCard = cardList.get(ChooseCard - 1);
            return true;
        }

        boolean last4same = true;
        for (int i = 2; i < ChooseCard; i++) {
            if (!Objects.equals(cardList.get(i).CardNum, cardList.get(1).CardNum)) {
                last4same = false;
                break;
            }
        }
        if (last4same) {
            siTiaoCard = cardList.get(1);
            siTiaoRemainCard = cardList.get(0);
            return true;
        }

        return false;
    }


    private boolean isHulu(List<Card> cardList) {
        for (int i = 0; i < ChooseCard; i++) {
            for (int j = i + 1; j < ChooseCard; j++) {
                for (int k = j + 1; k < ChooseCard; k++) {
                    if (Objects.equals(cardList.get(i).CardNum, cardList.get(j).CardNum) &&
                            Objects.equals(cardList.get(i).CardNum, cardList.get(k).CardNum)) {

                        int card1 = 0;
                        for (int t = 0; t < ChooseCard; t++) {
                            if (t != i && t != j && t != k) {
                                card1 = t;
                                break;
                            }
                        }
                        int card2 = 0;
                        for (int t = card1 + 1; t < ChooseCard; t++) {
                            if (t != i && t != j && t != k) {
                                card2 = t;
                                break;
                            }
                        }

                        if (Objects.equals(cardList.get(card1).CardNum, cardList.get(card2).CardNum)) {
                            huluCard = cardList.get(i);
                            huluRemainCard = cardList.get(card1);
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    private boolean isTonghua(List<Card> cardList) {
        CardType firstCardType = cardList.get(0).getCardType();
        for (int i = 1; i < ChooseCard; i++) {
            if (!Objects.equals(cardList.get(i).CardType, firstCardType)) {
                return false;
            }
        }
        return true;
    }

    private boolean isShunZi(List<Card> cardList) {
        for (int i = 1; i < ChooseCard; i++) {
            if (CardCommon.GetCardNumberScore(cardList.get(i).CardNum) + 1 != CardCommon.GetCardNumberScore(cardList.get(i - 1).CardNum)) {
                return false;
            }
        }
        return true;
    }

    private boolean isSantiao(List<Card> cardList) {
        for (int i = 0; i < ChooseCard; i++) {
            for (int j = i + 1; j < ChooseCard; j++) {
                for (int k = j + 1; k < ChooseCard; k++) {
                    if (Objects.equals(cardList.get(i).CardNum, cardList.get(j).CardNum) &&
                            Objects.equals(cardList.get(i).CardNum, cardList.get(k).CardNum)) {
                        santiaoCard = cardList.get(i);

                        santiaoRemainCardList = new ArrayList<>();
                        for (int t = 0; t < ChooseCard; t++) {
                            if (t != i && t != j && t != k) {
                                santiaoRemainCardList.add(cardList.get(t));
                            }
                        }
                        santiaoRemainCardList.sort(((o1, o2) -> (int) (CardCommon.GetCardNumberScore(o2.CardNum) - CardCommon.GetCardNumberScore(o1.CardNum))));
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private boolean isLiangDui(List<Card> cardList) {
        if (Objects.equals(cardList.get(0).CardNum, cardList.get(1).CardNum) && Objects.equals(cardList.get(2).CardNum, cardList.get(3).CardNum)) {
            liangDuiCard1 = cardList.get(0);
            liangDuiCard2 = cardList.get(2);
            liangDuiRemainCard = cardList.get(4);
            return true;
        } else if (Objects.equals(cardList.get(0).CardNum, cardList.get(1).CardNum) && Objects.equals(cardList.get(3).CardNum, cardList.get(4).CardNum)) {
            liangDuiCard1 = cardList.get(0);
            liangDuiCard2 = cardList.get(3);
            liangDuiRemainCard = cardList.get(2);
            return true;
        } else if (Objects.equals(cardList.get(1).CardNum, cardList.get(2).CardNum) && Objects.equals(cardList.get(3).CardNum, cardList.get(4).CardNum)) {
            liangDuiCard1 = cardList.get(1);
            liangDuiCard2 = cardList.get(3);
            liangDuiRemainCard = cardList.get(0);
            return true;
        }
        return false;
    }

    private boolean isDuiZi(List<Card> cardList) {
        for (int i = 0; i < ChooseCard; i++) {
            for (int j = i + 1; j < ChooseCard; j++) {
                if (Objects.equals(cardList.get(i).CardNum, cardList.get(j).CardNum)) {
                    duiziCard = cardList.get(i);
                    duiziRemainCardList = new ArrayList<>();
                    for (int t = 0; t < ChooseCard; t++) {
                        if (t != i && t != j) {
                            duiziRemainCardList.add(cardList.get(t));
                        }
                    }
                    duiziRemainCardList.sort(((o1, o2) -> (int) (CardCommon.GetCardNumberScore(o2.CardNum) - CardCommon.GetCardNumberScore(o1.CardNum))));
                    return true;
                }
            }
        }
        return false;
    }

}
